#pragma once

struct hBitStr
{
	uint8_t _beg = 0;
	uint8_t _end = 0;
	std::deque<size_t> _data;

	hBitStr& operator<<(uint64_t ul);
	template <size_t N>
	hBitStr& operator>>(std::bitset<N>& s);
	hBitStr& operator>>(bool& b);
	explicit operator bool() { return _beg != _end; }

	std::ostream& fillOs(std::ostream& os) const;
};

constexpr size_t dtBitSize = std::ratio_multiply<std::ratio<sizeof(std::_Get_first_parameter<decltype(hBitStr::_data)>::type)>, std::ratio<8>>::num;
constexpr size_t dtBitMask = std::ratio_subtract<std::ratio<dtBitSize>, std::ratio<1>>::num;
constexpr size_t dtBitOffset = std::ratio_subtract<std::ratio<std::bit_width(dtBitSize)>, std::ratio<1>>::num;

std::ostream& operator<<(std::ostream& os, const hBitStr& str);
namespace _hBitStrDetail
{
	union Bit8;
	template <bool IsConst>
	struct Bit
	{
		using OwnerTy = std::conditional_t<IsConst, const Bit8, Bit8>;
		OwnerTy& _owner;
		uint8_t _id;

		Bit& operator=(bool b);
		operator bool() const;
	};

	union Bit8
	{
		int8_t _val = 0;
		uint8_t _uval;

		Bit<false> operator[](uint8_t b) { return Bit<false>{ *this, b }; }
		Bit<true> operator[](uint8_t b) const { return Bit<true>{ *this, b }; }
		std::ostream& fillOs(std::ostream& os) const;
	};
}

#include "hBitStrImpl.h"